package site.lanmushan.framework.authorization;


import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import site.lanmushan.framework.authorization.service.TokenService;
import site.lanmushan.framework.authorization.strategy.ContextStorageStrategy;
import site.lanmushan.framework.cypher.md5.MD5Util;
import site.lanmushan.framework.exception.HTTPCode;
import site.lanmushan.framework.exception.OperateException;
import site.lanmushan.framework.util.ApplicationUtil;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author dy
 * @Date 2020/6/15 22:53
 * @Version 1.0
 */
@Slf4j
public class CurrentUserUtil {
    public final static String USER_KEY = "currentUser";
    public final static String AUTHORIZATION = "authorization";
    public final static String ADMIN_CODE = "admin";
    public final static String ANON_CODE = "anon";
    /**
     * 过期时间
     */
    private final static int AUTHORIZATION_EXPIRATION_TIME = 30 * 60 * 1000;
    public final static String REDIS_ONLINE_USER_KEY_PREFIX = "ONLINE_USER:";
    public final static String REDIS_API_HASH_KEY = "REDIS_API_HASH_KEY:";

    private static ContextStorageStrategy getContextStorageStrategy() {
        return ApplicationUtil.getBean(ContextStorageStrategy.class);
    }

    private static TokenService getTokenService() {
        return ApplicationUtil.getBean(TokenService.class);
    }

    public static String createPassword(String oldPassword, String salt) {
        return MD5Util.createMD5AndSalt(oldPassword, salt, 3);
    }

    public static boolean isLogin() {
        CurrentUser currentUser = getCurrentUser();
        return currentUser != null;
    }


    public static CurrentUser getCurrentUser(String token, String tokenSecretKey) {
        try {
            return getTokenService().decryptToken(token, tokenSecretKey, CurrentUser.class);
        } catch (Exception e) {
            //  log.error(e.getMessage(), e);
            return null;
        }
    }

    public static CurrentUser getCurrentUser(String token) {
        try {
            return getTokenService().decryptToken(token, CurrentUser.class);
        } catch (Exception e) {
            //  log.error(e.getMessage(), e);
            return null;
        }

    }

    /**
     * 只能在含有RequestContextHolder的依赖下使用
     * 1.首先在request.attribute中获取用户信息
     * 2.在token中获取
     * 3.在token中获取成功过后不直接返回，判断redis中是否过期；过期抛出异常，没有过期进行续期
     *
     * @return
     */
    public static CurrentUser getCurrentUser() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Object currentUserObj = request.getAttribute(USER_KEY);
        if (currentUserObj != null) {
            return (CurrentUser) currentUserObj;
        }
        String token = request.getHeader(AUTHORIZATION);
        CurrentUser currentUser = getCurrentUser(token);
        if (currentUser == null) {
            throw new OperateException(HTTPCode.E600);
        }
//        if (isLoginOverdue(currentUser, token)) {
//            request.setAttribute(USER_KEY, currentUser);
//        }
        return currentUser;
    }

    public static void setCurrentUser(CurrentUser currentUser) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        request.setAttribute(USER_KEY, currentUser);
    }

    public static void saveUserToRedis(CurrentUser currentUser, String token) {
        String redisUserKey = REDIS_ONLINE_USER_KEY_PREFIX + currentUser.getAccount();
        // getContextStorageStrategy().opsForValue().set(redisUserKey, token, AUTHORIZATION_EXPIRATION_TIME, TimeUnit.MILLISECONDS);
    }

    public static boolean isLoginOverdue(CurrentUser currentUser, String token) {
        if (currentUser == null) {
            throw new OperateException(HTTPCode.E600);

        }
        //     String redisUserKey = REDIS_ONLINE_USER_KEY_PREFIX + currentUser.getAccount();
//        Object value = getContextStorageStrategy().opsForValue().get(redisUserKey);
//        if (value == null) {
//            throw new OperateException(HTTPCode.E602);
//        }
//        //用户只能在一个地方登陆，如果允许多端登录修改规则
//        if (token.equals(value)) {
//            getContextStorageStrategy().expire(redisUserKey, AUTHORIZATION_EXPIRATION_TIME, TimeUnit.MILLISECONDS);
//        } else {
//            throw new OperateException(HTTPCode.E600, "您的账号已经在其他地方登录或登录过期");
//        }
        return true;
    }

    /**
     * 验证指定Uri权限
     *
     * @param uri
     * @param currentUser
     * @return
     */
    public static Boolean currentUserHasUriPermissions(String uri, CurrentUser currentUser) {
        Authority authority = getContextStorageStrategy().getPermissionAuthorityByKey(uri);
        if (authority == null) {
            return false;
        }

        List roleCodes = authority.getRoleCodes();
        if (roleCodes == null) {
            return false;
        }
        if (roleCodes.contains(ANON_CODE)) {
            return true;
        }
        if (currentUser == null) {
            return false;
        }
        List<String> userCodes = authority.getUserCodes();
        ;
        if (userCodes == null) {
            userCodes = new ArrayList<>(0);
        }
        return roleCodes.contains(ANON_CODE) || roleCodes.containsAll(currentUser.getRoleCodes()) || userCodes.contains(currentUser.getAccount());
    }

    public static Boolean currentUserHasUriPermissions(String uri) {
        CurrentUser currentUser = getCurrentUser();
        return currentUserHasUriPermissions(uri, currentUser);
    }

    public static void main(String args[]) {
        CurrentUser currentUser = new CurrentUser();
        currentUser.setAccount("asdfasfsa");
        currentUser.setNickName("xxxxx");
        currentUser.setUserId(1000000L);
        currentUser.setSex(1);

    }
}
